#!/usr/bin/evn python
# -*- coding: utf-8 -*-
"""
description: please input using description
author: justbk
date: 2021/7/5
modify_records:
    - 2021/7/5 justbk create this file
"""
import threading
import functools
import inspect


class Singleton:
    objs = {}
    objs_init = {}
    object_lock = threading.Lock()

    def __new__(cls, *args, **kwargs):
        cls_name = cls.get_unique_key()
        if cls_name in Singleton.objs:
            return Singleton.objs[cls_name]['obj']
        with Singleton.object_lock:
            if cls_name in Singleton.objs:
                return Singleton.objs[cls_name]['obj']
            _obj = object.__new__(cls, *args, **kwargs)
            Singleton.objs[cls_name] = {'obj': _obj, 'init': False}
            if cls_name not in Singleton.objs_init:
                Singleton.objs_init[cls_name] = cls.__init__
            setattr(cls, "__init__", cls.decorate_init(Singleton.objs_init[cls_name]))
        return Singleton.objs[cls_name]['obj']


    @classmethod
    def decorate_init(cls, fn):
        @functools.wraps(fn)
        def wrap(*args, **kwargs):
            key = cls.get_unique_key()
            if Singleton.objs[key]['init']:
                return
            with Singleton.object_lock:
                if Singleton.objs[key]['init']:
                    return
                fn(*args, **kwargs)
                Singleton.objs[key]['init'] = True
        return wrap

    @classmethod
    def get_unique_key(cls):
        return cls.__name__

    @classmethod
    def clear(cls):
        key = cls.get_unique_key()
        if key == Singleton.get_unique_key():
            with Singleton.object_lock:
                Singleton.objs.clear()
                return
        if key not in Singleton.objs:
            return
        with Singleton.object_lock:
            Singleton.objs.pop(key)


